package com.hy.admin.service.impl;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.hy.admin.dao.CourseOrderDao;
import com.hy.admin.dao.PayOrderDao;
import com.hy.admin.dao.YangCardOrderDao;
import com.hy.admin.entity.PayOrderEntity;
import com.hy.admin.enums.EnumPayModel;
import com.hy.admin.enums.EnumPayOrderStatus;
import com.hy.admin.enums.EnumPayResultStatus;
import com.hy.admin.enums.EnumPayState;
import com.hy.admin.helper.ResultUtil;
import com.hy.admin.helper.UNISOrderBuilder;
import com.hy.admin.helper.WechatConfig;
import com.hy.admin.helper.request.PayOrderByParam;
import com.hy.admin.helper.request.TradeRequest;
import com.hy.admin.service.CourseService;
import com.hy.admin.service.PayService;
import com.hy.admin.service.YangCoinService;
import com.hy.config.ConfigurationUtils;
import com.hy.core.response.ServicesResult;
import com.hy.utils.CommonUtility;
import com.hy.utils.HyRequestHandler;
import com.hy.utils.MD5Util;
import org.apache.commons.httpclient.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Created by wayne on 18/4/22.
 */
@Service
public class PayServiceImpl implements PayService {
    protected final Logger logBase = LoggerFactory.getLogger(PayServiceImpl.class);
    @Autowired
    private PayOrderDao payOrderDao;
    @Autowired
    private YangCardOrderDao yangCardOrderDao;
    @Autowired
    private CourseService courseService;
    @Autowired
    private YangCoinService yangCoinService;

    @Override
    public ServicesResult<String> confirmOrder(TradeRequest tradeRequest,String domain) {
        ServicesResult<String> servicesResult = new ServicesResult<>();
        PayOrderByParam parm = new PayOrderByParam();
        parm.setOutOrderNo(tradeRequest.getOutOrderNo());
        parm.setOutOrderType(tradeRequest.getOutOrderType());
        PayOrderEntity payOrder = payOrderDao.selectOneByParam(parm);
        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
        EnumPayResultStatus enumPayResultStatus = EnumPayResultStatus.RETURN201;
        //默认走APP支付
        WechatConfig wechatConfig = new WechatConfig();
        if(payOrder!=null){
            servicesResult.setResult(gson.toJson(ResultUtil.result(null, payOrder,null)));
            return servicesResult;
        }
        //if (payOrder == null||!payOrder.ispaying()) {
            payOrder = new PayOrderEntity();
            payOrder.setGoodsDescribe(tradeRequest.getSubject());
            payOrder.setOutOrderId(tradeRequest.getOutOrderId());
            payOrder.setMemberId(tradeRequest.getMemberId());
            payOrder.setMchId(wechatConfig.getMchId());
            payOrder.setAuthCode(tradeRequest.getAuthCode());
            payOrder.setOutOrderNo(tradeRequest.getOutOrderNo());
            payOrder.setOrderNo(UNISOrderBuilder.GeneratorOrderNo(tradeRequest.getOutOrderNo(),tradeRequest.getOutOrderType()));
            payOrder.setOutOrderType(tradeRequest.getOutOrderType());
            payOrder.setPayAmount(new BigDecimal(tradeRequest.getPayAmount()));
            payOrder.setRequestTime(new Date());
            payOrder.setPayMode(tradeRequest.getPayMode());
            payOrder.setCreateId(new Long(1));
            payOrder.setUpdateId(new Long(1));
            payOrder.setUpdateTime(new Date());
            payOrder.setCreateTime(new Date());
            payOrder.setStatus(EnumPayOrderStatus.DUE_PAY.getId());
            payOrder.setRequestIp(tradeRequest.getRequestIp());
            payOrderDao.save(payOrder);
        //}
        SortedMap<String, String> packageParams = new TreeMap<String, String>();

        if (null == tradeRequest.getSubject() || "".equals(tradeRequest.getSubject())) {
            packageParams.put("body", "订单号：" + System.currentTimeMillis()+"_"+payOrder.getOrderNo());
        }
        else {
            packageParams.put("body", payOrder.getGoodsDescribe());
        }

        packageParams.put("mch_id", wechatConfig.getMchId());//商户号
        packageParams.put("appid", wechatConfig.getAppId());//公众号ID
        String nonceStr = CommonUtility.getNonceStr();//随机字符串
        packageParams.put("out_trade_no", System.currentTimeMillis()+"_"+payOrder.getOrderNo());
        packageParams.put("nonce_str", nonceStr);
        packageParams.put("sign_type", "MD5");

        packageParams.put("total_fee", CommonUtility.yuanToFen(payOrder.getPayAmount().toString()));//金额
        packageParams.put("spbill_create_ip", tradeRequest.getRequestIp());
        packageParams.put("trade_type", tradeRequest.getPayMode() == EnumPayModel.WECHAT_JSAPIPAY.getId() ? "JSAPI" : "APP");
        packageParams.put("notify_url", domain+"/api/pay/wechartback");
        if(tradeRequest.getPayMode() == EnumPayModel.WECHAT_JSAPIPAY.getId()){
            packageParams.put("appid", ConfigurationUtils.getString("weixin_app_id"));//公众号ID
            packageParams.put("openid", tradeRequest.getOpenid());
            packageParams.put("trade_type", "JSAPI");
        }else{
            packageParams.put("trade_type", "APP");
        }
        String sign = HyRequestHandler.createSign(packageParams, wechatConfig.getAppKey());
        packageParams.put("sign", sign);
        String xmlParm = HyRequestHandler.parseSimpleXML(packageParams);
        String resData = "";
        Map mapResult = null;

        try {
            resData = HyRequestHandler.requestWithoutCert("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlParm, null);
            mapResult = HyRequestHandler.xmlToMap(resData);
            payOrder.setStatus(EnumPayOrderStatus.PAYING.getId());
        } catch (Exception e) {
            logBase.error("请求异常", e);
        }
        SortedMap<String, String> resultParams=null;
        String returnCode = (String) mapResult.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
            String resultCode = (String) mapResult.get("result_code");
            if ("SUCCESS".equals(resultCode)) {
                String prepay_id = mapResult.get("prepay_id").toString();
                payOrder.setPayUrl(prepay_id);
                resultParams = new TreeMap<String, String>();
                if(tradeRequest.getPayMode() == EnumPayModel.WECHAT_JSAPIPAY.getId()){
                    resultParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
                    resultParams.put("nonceStr", CommonUtility.getNonceStr());
                    resultParams.put("appId", ConfigurationUtils.getString("weixin_app_id"));//公众号ID
                    resultParams.put("package", "prepay_id="+prepay_id);
                    resultParams.put("signType", "MD5");
                }else {
                    resultParams.put("appid", wechatConfig.getAppId());
                    resultParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
                    resultParams.put("noncestr", CommonUtility.getNonceStr());
                    resultParams.put("partnerid", wechatConfig.getMchId());
                    resultParams.put("package", "Sign=WXPay");
                    resultParams.put("prepayid", prepay_id);
                }
                resultParams.put("sign", HyRequestHandler.createSign(resultParams, wechatConfig.getAppKey()));

            } else {
                payOrder.setStatus(EnumPayOrderStatus.PAY_FAIL.getId());
                enumPayResultStatus = EnumPayResultStatus.RETURN203;
            }
            if (mapResult.containsKey("err_code_des")) {
                payOrder.setMessage(mapResult.get("err_code_des").toString());
            }
            payOrderDao.update(payOrder);
        } else {
            payOrder.setStatus(EnumPayOrderStatus.PAY_FAIL.getId());
            enumPayResultStatus = EnumPayResultStatus.RETURN203;
            payOrder.setMessage(mapResult.get("return_msg").toString());
        }
        String payData=ResultUtil.replaceBlank(gson.toJson(resultParams));
        servicesResult.setResult(gson.toJson(ResultUtil.result(enumPayResultStatus, payOrder,payData)));

        return servicesResult;
    }

    @Override
    public ServicesResult<String> queryOrder(TradeRequest tradeRequest) {
        ServicesResult<String> servicesResult = new ServicesResult<>();
        PayOrderByParam parm = new PayOrderByParam();
        if(tradeRequest.getOutOrderId()!=null){
            parm.setOutOrderId(tradeRequest.getOutOrderId());
        }
        if(tradeRequest.getOrderNo()!=null){
            parm.setOrderNo(tradeRequest.getOrderNo());
        }
        parm.setOutOrderType(tradeRequest.getOutOrderType());
        parm.setOutOrderNo(tradeRequest.getOutOrderNo());
        PayOrderEntity payOrder = payOrderDao.selectOneByParam(parm);
        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
        EnumPayResultStatus enumPayResultStatus = EnumPayResultStatus.RETURN201;
        if (payOrder == null) {
            servicesResult.setResult(gson.toJson(ResultUtil.result(tradeRequest)));
            return servicesResult;
        }
        SortedMap<String, String> resultParams = null;
        resultParams = new TreeMap<String, String>();
        WechatConfig wechatConfig = new WechatConfig();
        resultParams.put("appid", wechatConfig.getAppId());
        resultParams.put("partnerid", wechatConfig.getMchId());
        resultParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        resultParams.put("noncestr", CommonUtility.getNonceStr());
        resultParams.put("package", "Sign=WXPay");
        resultParams.put("prepayid", payOrder.getPayUrl());
        resultParams.put("sign", HyRequestHandler.createSign(resultParams, wechatConfig.getAppKey()));
        String payData = ResultUtil.replaceBlank(gson.toJson(resultParams));
        servicesResult.setResult(gson.toJson(ResultUtil.result(null, payOrder, payData)));
        return servicesResult;
    }

    @Override
    public ServicesResult<Boolean> handlerOrder(Map mapResult) {
        ServicesResult<Boolean> servicesResult = new ServicesResult<>();
        String mechId = (String) mapResult.get("mch_id");
        String orderNo = (String) mapResult.get("out_trade_no");
        String result_code = (String) mapResult.get("result_code");
        String transaction_id = (String) mapResult.get("transaction_id");
        String time_end = (String) mapResult.get("time_end");
        Date finishTime = CommonUtility.strToTimeIsSecond((String) mapResult.get("time_end"));
        String openid = (String) mapResult.get("openid");
        PayOrderByParam parm = new PayOrderByParam();
        orderNo = orderNo.contains("_") ? orderNo.substring(orderNo.indexOf("_")+1) : orderNo;
        System.out.println("orderNo="+orderNo);
        parm.setOrderNo(orderNo);
        PayOrderEntity payOrder = payOrderDao.selectOneByParam(parm);
        if (payOrder == null || !result_code.equals("SUCCESS")) {
            servicesResult.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
            servicesResult.setResult(false);
            return servicesResult;
        }
        payOrder.setStatus(EnumPayOrderStatus.PAY_SUCCESS.getId());
        payOrder.setFinishTime(finishTime);
        payOrder.setPaymentSn(transaction_id);
        payOrderDao.update(payOrder);
        logBase.info("payOrder status haved update {}/{}", payOrder.getOrderNo(),payOrder.getOutOrderType());
        servicesResult.setResult(true);
        if (payOrder.getOutOrderType().intValue() == 1) {
            logBase.info("yangCardOrder status begin update {}", payOrder.getOrderNo());
            yangCardOrderDao.changePayState(payOrder.getOutOrderId(), EnumPayState.PAID.getId());
            logBase.info("yangCardOrder status haved update {}", payOrder.getOrderNo());
        } else if (payOrder.getOutOrderType().intValue() == 2) {
            logBase.info("courseOrder status begin update {}", payOrder.getOrderNo());
            try {
                courseService.paySuccess(payOrder.getOutOrderId());
            } catch (Exception e) {
                logBase.info("courseOrder status update failed{}", payOrder.getOrderNo());
            }
            logBase.info("courseOrder status haved update {}", payOrder.getOrderNo());
        } else if (payOrder.getOutOrderType().intValue() == 3) {
            logBase.info("yangCoinOrder status begin update {}", payOrder.getOrderNo());
            try {
                yangCoinService.paySuccess(payOrder.getOutOrderId());
            } catch (Exception e) {
                logBase.info("yangCoinOrder status update failed{}", payOrder.getOrderNo());
            }
            logBase.info("yangCoinOrder status haved update {}", payOrder.getOrderNo());
        }
        return servicesResult;
    }


}
